
package com.trp.view;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;

import com.trp.model.CIMModel;
import com.trp.service.ILoaderService;
import com.trp.service.QueryModelType;

public class Workspace extends ViewGroup implements ViewLoader {

    private List<GISView> l = new ArrayList<GISView>(0);

    public Workspace(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public Workspace(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public Workspace(Context context) {
        super(context);
    }

    private int lastX = 0;

    private int lastY = 0;

    private int trX = 0;

    private int trY = 0;

    private int lastX1 = 0;

    private int lastY1 = 0;

    private int offsetX = 0;

    private int offsetY = 0;

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            lastX = (int)event.getX(0);
            lastY = (int)event.getY(0);
            trX = lastX;
            trY = lastY;
            offsetX = 0;
            offsetY = 0;
            if (event.getPointerCount() > 1) {
                lastX1 = (int)event.getX(1);
                lastY1 = (int)event.getY(1);
            }
        } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
            // handle zoom in/out operation
            if (event.getPointerCount() > 1) {
                int MaxX = lastX > lastX1 ? lastX : lastX1;
                int MaxY = lastY > lastY1 ? lastY : lastY1;

                int newX = (int)(event.getX(0) > event.getX(1) ? event.getX(0) : event.getX(1));
                int newY = (int)(event.getY(0) > event.getY(1) ? event.getY(0) : event.getY(1));

                float scaleF = (newX > MaxX || newY > MaxY) ? 1.05F : 0.95F;
                scale(scaleF);
                this.invalidate();
                lastX = (int)event.getX(0);
                lastY = (int)event.getY(0);
                lastX1 = (int)event.getX(1);
                lastY1 = (int)event.getY(1);
                // handle pan operation
            } else if (event.getPointerCount() == 1) {
                trX = (int)event.getX() - lastX + offsetX;
                trY = (int)event.getY() - lastY + offsetY;
                lastX = (int)event.getX();
                lastY = (int)event.getY();
                transate(trX, trY);
                this.invalidate();

                offsetX = 0;
                offsetY = 0;
            }
        } else if (event.getActionMasked() == MotionEvent.ACTION_POINTER_UP
                && event.getActionIndex() == 0) {
            offsetX = (int)event.getX() - lastX1;
            offsetY = (int)event.getY() - lastY1;
        }
        return true;
    }

    private void scale(float scaleX) {
        RectF screen = MapSettings.getInstance().getScreen();
        if (screen == null || screen.centerX() <= 0 || screen.centerY() <= 0) {
            return;
        }
        Transformation.getInstance().scale(scaleX,
                (int)MapSettings.getInstance().getScreen().centerX(),
                (int)MapSettings.getInstance().getScreen().centerY());
        if ((int)Transformation.getInstance().getScale() % 5 == 0) {
            dispatchScaleChange(scaleX);
        }
    }

    private void transate(int x, int y) {
        Transformation.getInstance().translate(x, y);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        if (changed) {
            MapSettings.getInstance().setScreen(new RectF(l, t, r, b));
            Transformation.getInstance().setMap(MapSettings.getInstance().getWorld(),
                    MapSettings.getInstance().getScreen());
        }
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        for (View v : l) {
            v.draw(canvas);
        }
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        this.onTouchEvent(ev);
        for (View p : l) {
            if (p.onTouchEvent(ev)) {
                break;
            }
        }
        return true;
    }

    private void dispatchScaleChange(float scale) {
        // TODO check scale first, because if cross scale, we have to load new
        // data
        for (GISView p : l) {
            p.scaleChanged(scale);
        }
    }

    public void load(ILoaderService loader) throws LoadException {
        if (loader == null) {
            throw new LoadException(" loader is null! ");
        }
        l.clear();
        Map m = null;
        try {
            m = loader.getModel(new QueryModelType(QueryModelType.Type.KV500));
        } catch (android.os.RemoteException e) {
            throw new LoadException(e);
        }
        if (m == null) {
            return;
        }

        new Builder().buildView(this.getContext(), l, (Map<String, CIMModel>)m);

        this.invalidate();
    }

    public void loadConfig(ILoaderService loader) throws LoadException {
        float l1 = 48031.1F;
        float t1 = 38150.2F;
        float r2 = 523688F;
        float bb = 3407990F;
        MapSettings.getInstance().setWorld(new RectF(l1, t1, r2, bb));
    }

    public void reset() {

    }

    public void unLoad() {
        l.clear();
        Transformation.getInstance().reset();
        MapSettings.getInstance().reset();
    }

    @Override
    public void removeAllViews() {
        super.removeAllViews();
        l.clear();
    }

    @Override
    public void addView(View child) {
        if (child == null) {
            throw new NullPointerException("child is null.");
        }
        super.addView(child);
        if (!(child instanceof GISView)) {
            throw new IllegalArgumentException("child is not GISView instance.");
        }
        l.add((GISView)child);
        child.invalidate();
    }

}
